#include "ds18b20_eswin.h"
#include "pins_driver.h"

#define DS18B20_DQ_LOW()                                                              \
    do {                                                                              \
        PINS_DRV_WritePinDirection(DS18B20_PORT, DS18B20_PIN, GPIO_OUTPUT_DIRECTION); \
        PINS_DRV_WritePin(DS18B20_PORT, DS18B20_PIN, 0);                              \
    } while (0)

#define DS18B20_DQ_HIGH()                                                            \
    do {                                                                             \
        PINS_DRV_WritePin(DS18B20_PORT, DS18B20_PIN, 1);                             \
        PINS_DRV_WritePinDirection(DS18B20_PORT, DS18B20_PIN, GPIO_INPUT_DIRECTION); \
    } while (0)

#define DS18B20_DQ_READ() ((PINS_DRV_ReadPins(DS18B20_PORT) >> DS18B20_PIN) & 0x01)

// DS18B20命令定义
#define DS18B20_CMD_CONVERT_T        0x44 // 启动温度转换
#define DS18B20_CMD_READ_SCRATCHPAD  0xBE // 读取暂存器
#define DS18B20_CMD_WRITE_SCRATCHPAD 0x4E // 写入暂存器
#define DS18B20_CMD_SKIP_ROM         0xCC // 跳过ROM

// 复位DS18B20
static ds18b20_error_t DS18B20_Reset(void)
{
    DS18B20_DQ_LOW();
    OS_DelayUs(480); // 保持480μs低电平

    DS18B20_DQ_HIGH();
    OS_DelayUs(70); // 等待15-60μs

    // 检测存在脉冲
    if (DS18B20_DQ_READ() == 0) {
        // 等待存在脉冲结束
        uint32_t timeout = 100;
        while (!DS18B20_DQ_READ() && timeout--) {
            OS_DelayUs(1);
        }
        if (timeout == 0)
            return DS18B20_ERROR_TIMEOUT;

        OS_DelayUs(410); // 等待复位周期完成
        return DS18B20_OK;
    }

    return DS18B20_ERROR_NO_DEVICE;
}

// 向DS18B20写入1位
static void DS18B20_WriteBit(uint8_t bit)
{
    DS18B20_DQ_LOW();

    if (bit) {
        OS_DelayUs(6); // 拉低1-15μs
        DS18B20_DQ_HIGH();
        OS_DelayUs(64); // 完成时间槽
    } else {
        OS_DelayUs(60); // 保持60μs低电平
        DS18B20_DQ_HIGH();
        OS_DelayUs(10); // 恢复时间
    }
}

// 从DS18B20读取1位
static uint8_t DS18B20_ReadBit(void)
{
    uint8_t bit = 0;

    DS18B20_DQ_LOW();
    OS_DelayUs(6); // 拉低1-15μs

    DS18B20_DQ_HIGH();
    OS_DelayUs(9); // 等待15μs内采样

    if (DS18B20_DQ_READ()) {
        bit = 1;
    }

    OS_DelayUs(55); // 完成时间槽
    return bit;
}

// 向DS18B20写入1字节
static void DS18B20_WriteByte(uint8_t byte)
{
    for (int i = 0; i < 8; i++) {
        DS18B20_WriteBit(byte & 0x01);
        byte >>= 1;
    }
}

// 从DS18B20读取1字节
static uint8_t DS18B20_ReadByte(void)
{
    uint8_t byte = 0;

    for (int i = 0; i < 8; i++) {
        byte >>= 1;
        if (DS18B20_ReadBit()) {
            byte |= 0x80;
        }
    }

    return byte;
}

status_t DS18B20_Init(void)
{
    // 配置引脚为开漏输出模式（需要外部上拉电阻）
    PINS_DRV_SetMuxModeSel(DS18B20_PORT, DS18B20_PIN, PORT_MUX_ALT1);
    PINS_DRV_SetPullSel(DS18B20_PORT, DS18B20_PIN, PORT_INTERNAL_PULL_NOT_ENABLED);
    DS18B20_DQ_HIGH();

    // 测试传感器响应
    return (DS18B20_Reset() == DS18B20_OK) ? STATUS_SUCCESS : STATUS_ERROR;
}

ds18b20_error_t DS18B20_SetResolution(ds18b20_resolution_t resolution)
{
    // 发送复位脉冲
    ds18b20_error_t err = DS18B20_Reset();
    if (err != DS18B20_OK)
        return err;

    // 发送跳过ROM命令
    DS18B20_WriteByte(DS18B20_CMD_SKIP_ROM);

    // 发送写暂存器命令
    DS18B20_WriteByte(DS18B20_CMD_WRITE_SCRATCHPAD);

    // 写入配置：TH, TL, 配置寄存器
    DS18B20_WriteByte(0);          // TH (报警上限)
    DS18B20_WriteByte(0);          // TL (报警下限)
    DS18B20_WriteByte(resolution); // 配置寄存器

    return DS18B20_OK;
}

ds18b20_error_t DS18B20_ReadTemperature(ds18b20_data_t *data)
{
    if (data == NULL)
        return DS18B20_ERROR_CHECKSUM;
    data->valid = false;

    // 发送复位脉冲
    ds18b20_error_t err = DS18B20_Reset();
    if (err != DS18B20_OK)
        return err;

    // 发送跳过ROM命令
    DS18B20_WriteByte(DS18B20_CMD_SKIP_ROM);

    // 发送启动转换命令
    DS18B20_WriteByte(DS18B20_CMD_CONVERT_T);

    // 等待转换完成 (根据分辨率不同，等待时间不同)
    // 这里使用简单的总线检测方式
    uint32_t timeout = 750; // 12位分辨率最大750ms
    while (timeout--) {
        if (DS18B20_DQ_READ()) { // 转换完成时总线变高
            break;
        }
        OS_DelayUs(1000);
    }

    if (timeout == 0) {
        return DS18B20_ERROR_CONVERSION;
    }

    // 重新初始化总线
    err = DS18B20_Reset();
    if (err != DS18B20_OK)
        return err;

    // 发送跳过ROM命令
    DS18B20_WriteByte(DS18B20_CMD_SKIP_ROM);

    // 发送读取暂存器命令
    DS18B20_WriteByte(DS18B20_CMD_READ_SCRATCHPAD);

    // 读取9字节暂存器数据
    uint8_t scratchpad[9];
    for (int i = 0; i < 9; i++) {
        scratchpad[i] = DS18B20_ReadByte();
    }

    // 校验CRC
    uint8_t crc = 0;
    for (int i = 0; i < 8; i++) {
        crc = crc ^ scratchpad[i];
        for (int j = 0; j < 8; j++) {
            if (crc & 0x01) {
                crc = (crc >> 1) ^ 0x8C;
            } else {
                crc >>= 1;
            }
        }
    }

    if (crc != scratchpad[8]) {
        return DS18B20_ERROR_CHECKSUM;
    }

    // 解析温度值
    int16_t raw_temp = (scratchpad[1] << 8) | scratchpad[0];

    // 检查符号位（Bit 15）
    if (raw_temp & 0x8000) {
        // 负温度：取补码（按位取反后加1）
        raw_temp          = ~raw_temp + 1;
        data->is_negative = true;
    } else {
        data->is_negative = false;
    }
    int16_t integer  = (raw_temp >> 4) & 0x07FF;
    uint16_t decimal = raw_temp & 0x000F; // 低4位
    if (integer == 85) {
        data->valid = false;
    } else {
        data->temperature_integer = integer; // 12位分辨率，0.0625°C/LSB
        data->temperature_decimal = decimal * 625;
        data->valid               = true;
    }
    return DS18B20_OK;
}
